Unity3D Building Damage Tutorial- Part XI - Hovering parts destruction
Today I'll try to cope with parts hovering as a result of fire. But before, I've made a tiny change in way the Aliases are updated. Before, the TellAliasesToUpdate method was called every time the Building class is updated. Than, the update is passed to Aliases if an internal times comes to certain second, now 1. if(time>1){ for(int k=0; k1){ for(int k=0; k0){ DebGeneralNumber++; DebGeneralDestroyTime += DebDestroyTime; } } So every time this method is called, Aliases are updated. Now, to simulate fire, First Click, to start fire, than click A to update. Hovering Elements So, lets say that we start fire sequence. After some moments, we will have hovering parts of mesh. This is of course natural consequence of the way our fire is spreading. But as it looks unrealistic, we have to find a way to localise these parts and destroy them. SetGroundAliases method But first, we have to acknowledge what in fact are "hovering" parts. I decided to introduce "Ground Aliases". These are special, Indestructible Aliases that symbolise the points where mesh connects to the ground. private void SetGroundAliases(float percent){//You give the percent of height from which Aliases becomes Ground-Aliases. 0.1f makes lowest 10% of Aliases a Ground-Aliases percent = 1 - percent; float CuttingPosition = MaximumHeight - (MaximumHeight-MinimumHeight)*percent; foreach(Verticle v in Aliases){ if(v.positionAbsolute.y<-- here return; } So, now a "Hovering Alias" is an Alias that has no connection via LinkedAliases or LinksToOtherBranches to a "Ground Alias". ManageHoveringParts method Some simple general function. private void ManageHoveringParts(){ if( NumberOfGroundAliases 0 ){//without groud aliases everything would fall, so there is no point in calculating return; } List HoveringAliases = FindHoveringAliases(); foreach(int i in HoveringAliases){ Aliasesi.ImmediatelyDestroy(); } //We dont have to update mesh.traingles of Traingles List here as it will be called after this function is started //And in Alises we use just LinkedAliases and LinksToOtherBranches which are updated on-spot } FindHoveringAliases private List FindHoveringAliases(){//returns list containing numbers of Aliases that doesn't have connections to the GroundAliases List OutList = new List(); List AliasesArleadyChecked = new List(); int HowManyAliasesToCheck; if( IsMeshThick ){ HowManyAliasesToCheck = Aliases.Count/2; } else { HowManyAliasesToCheck = Aliases.Count; }//I just dont want to check twins, as they do the same as Aliases they are connected to for( int i = 0; i AliasesCurrentlyChecked = new List();//a list of Aliases that are checked this time for-loop is made. CheckForGroundAliasesAndSentFurther(i, AliasesArleadyChecked, AliasesCurrentlyChecked, ref ThereIsGroundAlias); if(ThereIsGroundAlias false){ OutList = OutList.Concat(AliasesCurrentlyChecked).ToList(); } } } return OutList; } Well, the point of this function is to make a list of ints - numbers of Aliases which are "hovering". It is implemented in similar way to dividing aliases into branches. Most important function called is CheckForGroundAliasesAndSentFurther. CheckForGroundAliasesAndSendFurther private void CheckForGroundAliasesAndSentFurther(int NumberBeingChecked, List AliasesArleadyChecked, List AliasesThatAreCheckInThisLoop, ref bool ThereIsGroundAlias){ if( !AliasesNumberBeingChecked.IsATwin ){//We shoudnt check twins, as they are just like its Main Alias AliasesThatAreCheckInThisLoop.Add(NumberBeingChecked); AliasesArleadyChecked.Add (NumberBeingChecked);//telling that we checked it if( AliasesNumberBeingChecked.state VerticleState.Ground ){//checking ThereIsGroundAlias = true; } foreach(int i in AliasesNumberBeingChecked.LinkedAliases){//Sending further (if necessary) if( !AliasesArleadyChecked.Contains(i) ){ CheckForGroundAliasesAndSentFurther(i, AliasesArleadyChecked, AliasesThatAreCheckInThisLoop, ref ThereIsGroundAlias); } } foreach(int i in AliasesNumberBeingChecked.LinksToOtherBranches){//Again Sending further (if necessary) if( !AliasesArleadyChecked.Contains(i) ){ CheckForGroundAliasesAndSentFurther(i, AliasesArleadyChecked, AliasesThatAreCheckInThisLoop, ref ThereIsGroundAlias); } } } } Maybe I'll start from the parameters: *NumberBeingChecked is a number of alias we will be checking in this method, and from which we will be sending check to its LinkedAliases. *AliasesArleadyChecked is a list of Aliases numbers Generally checked, this list prevents allowing calling this function twice on this Alias. *AliasesCurrentlyChecked Function checked in current for loop in FindHoveringAliases method. Very important list, talk about it in a second. *ThereIsGroundAlias A ref to bool from FindHoveringAliases Just when a GroundAlias is found in this "branch" there bool in FindHoveringAliases is turned to true. Two foreach is bottom of function is calling CheckForGroundAliasesAndSendFurther for LinkedAliases and LinksToOtherBranches. Back to FindHoveringAliases for( int i = 0; i AliasesCurrentlyChecked = new List();//a list of Aliases that are checked this time for-loop is made. CheckForGroundAliasesAndSentFurther(i, AliasesArleadyChecked, AliasesCurrentlyChecked, ref ThereIsGroundAlias); if(ThereIsGroundAlias false){ OutList = OutList.Concat(AliasesCurrentlyChecked).ToList(); } } } When after checking a "branch" and still not finding any Ground Alias, the Aliases in checked "branch" (AliasesCurrentlyChecked) are added to OutList. Than, this list is returned. Back to ManageHoveringParts foreach(int i in HoveringAliases){ Aliasesi.ImmediatelyDestroy(); } //We dont have to update mesh.traingles of Traingles List here as it will be called after this function is started //And in Alises we use just LinkedAliases and LinksToOtherBranches which are updated on-spot } For each Hovering Alias, a new method, ImmediatelyDestroy is called ImmediatelyDestroy method (Vecticle.cs) public void ImmediatelyDestroy(){//don,t bother sending info to other aliases, just change Traingles list in MeshManager and verticleState DestroyTriangles(); state = VerticleState.Destroyed; for(int i = 0; i > DictionaryOfWalls = new Dictionary >();//Similar to finding edges, isn't it. //Well, now we are going check pair of Aliases used in walls. If the same pair of Aliases was used twice, it is a "plank" //Kay will be produced from Aliases numbers, and List will store the numbers of triangles for(int i = (Triangles.Count - ( NumberOfFillingTraingles/3 ) ); i() ); DictionaryOfWallskey.Add (i); } } } int[] NewTrianglesList = new intmesh.triangles.Length; //list on which we will perform modifications mesh.triangles.CopyTo(NewTrianglesList,0); bool modified = false; foreach(KeyValuePair< float, List > pair in DictionaryOfWalls){ if(pair.Value.Count>1){ modified = true; foreach(int i in pair.Value){ //We cannot just modify Triangles List as UpdateTrianglesList modifies only the Original Traingles (not walls or filling ones) NewTrianglesListi*3 = 0; NewTrianglesListi*3+1 = 0; NewTrianglesListi*3+2 = 0; //Well, now intresting thing. We deleted the triangle with two Aliases. But what with the one with two twins and one alias??? //Intresting thing: The traingle with two twins in added directly After the one with 2 Aliases and one twin. NewTrianglesListi*3+3 = 0; NewTrianglesListi*3+4 = 0; NewTrianglesListi*3+5 = 0; } } } if(modified true){ mesh.triangles = NewTrianglesList; } return modified; } In dictionary I'll use kay generated in the same way as in "Open Edges", Tutorial part X. The value is a list as sometimes from a pair of Aliases two traingles may be generated (effectively a double-side traingle, the ones we are looking for!). for(int i = (Triangles.Count - ( NumberOfFillingTraingles/3 ) ); i Well, this is an intresting part. What is i at the begining of loop. We have to realise in what order the traingles are placed in mesh.traingles and Triangles list. #First, there are original traingles from the mesh #Than, the traingles filling "Open Edges" #Finally, traingles from "walls" added during the Alias destruction. Note that destroyed traingles are not removed from the array and list, effecting the order. They are just converted to zeros. Note two more things: #We destroy "planks" inside the function, working with copy of mesh.traingles and than updating mesh.traingles. As a results, we will have to update Traingles List etc. #We return a bool telling us if some planks were searched&destroyed GetAliasesNumbersFromTraingle private Vector2 GetAliasesNumbersFromTraingle(Vector3 vec){//returns Two numbers which are NOT twins numbers, or Vector2.zero if there was only one Alias and two twins in Traingle if(vec Vector3.zero){//its arleady destroyed, no point in continuing return Vector2.zero; } int[] TempArray = new int3; //3 not 2 is becouse sometimes there might be errors when triangle with 3 normal aliases was given int HowManyAliasesWeArleadyHave = 0; for(int i=0; i<3; i++){ if( VerticleToAliasArray[ (int) veci ] < Aliases.Count/2 ){ TempArrayHowManyAliasesWeArleadyHave = VerticleToAliasArray[ (int) veci ]; HowManyAliasesWeArleadyHave++; } } if(HowManyAliasesWeArleadyHave 3){ Debug.Log("A good Traingle was passed: It had 3 Aliases and 0 Twins"); return Vector2.zero; }else if(HowManyAliasesWeArleadyHave 2){ return new Vector2( TempArray0, TempArray1); }else{ return Vector2.zero; } } Well, this method just check if given traingle "consists" of two normal aliases and one triangle, if so returns these Aliases' numbers, if not, returns Vector2.zero TellAliasesToUpdate method Final version of this method. (for now) public void TellAliasesToUpdate(){ for(int k=0; k